﻿using NVelocity;
using NVelocity.App;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using FrameWork.Core.Common;
using System.Configuration;
using System.Reflection;

namespace HYBY.Task.Repository.Dapper {

  /// <summary>
  /// debug模式下，修改SQL模板立即生效
  /// </summary>
  public class SqlStatementManager {
    private static readonly ConcurrentDictionary<string, SqlStatement> Dic = new ConcurrentDictionary<string, SqlStatement>();
    private static ConcurrentBag<string> _xmlFiles = new ConcurrentBag<string>();
    private static readonly object Locker = new object();

    internal static void Init() {
      ReadXml();
      Velocity.Init();
    }

    internal static ConcurrentDictionary<string, SqlStatement> SqlStatements {
      get { return Dic; }
    }

    /// <summary>
    /// 从应用程序集中加载SQL语句配置文件
    /// </summary>
    private static void ReadXml() {
      String MappingAssembly = ConfigurationManager.AppSettings["MappingAssembly"];
      Assembly assembly = Assembly.Load(MappingAssembly);
      List<String> Mappings = assembly.GetManifestResourceNames().Where(p => p.EndsWith(".xml")).ToList();
      XDocument doc;
      foreach (String Mapping in Mappings) {
        Stream stream = assembly.GetManifestResourceStream(Mapping);
        doc =  XDocument.Load(stream);
        if (doc == null) {
          return;
        }
        var xElement = doc.Document.Element("statements");
        if (xElement == null) continue;
        var q = xElement.Elements("statement");
        foreach (var i in q) {
          var xAttribute = i.Attribute("id");
          var xAttribute2 = i.Attribute("cached");
          var xAttribute3 = i.Attribute("expired");
          var xAttribute4 = i.Attribute("primarykey");
          //一下几个属性只有用到存储过程分页的时候才需要填写
          var xAttribute5 = i.Attribute("sourcename");
          var xAttribute6 = i.Attribute("where");
          var xAttribute7 = i.Attribute("order");
          var xAttribute8 = i.Attribute("group");
          if (xAttribute != null) {
            string key = xAttribute.Value;
            string text = i.Value;

            if (string.IsNullOrEmpty(key) || string.IsNullOrWhiteSpace(text))
              return;

            if (Dic.ContainsKey(key))
              throw new ApplicationException(string.Format("{0} repeate!", key));

            Dic[key] = new SqlStatement {
              IsCached = xAttribute2 != null && (bool.Parse(xAttribute2.Value)),
              StatementId = key,
              StatementText = i.Value,
              Expired = xAttribute3 == null ? 0 : int.Parse(xAttribute3.Value),
              PrimaryKey = xAttribute4 == null ? "none" : xAttribute4.Value,
              SourceName = xAttribute5 == null ? "none" : xAttribute5.Value,
              Where = xAttribute6 == null ? "" : xAttribute6.Value,
              Order = xAttribute7 == null ? "" : xAttribute7.Value,
              Group = xAttribute8 == null ? "" : xAttribute8.Value
            };
          }
        }
      }
      /*string filePath = ConfigurationManager.AppSettings["SQLXmlPath"];//C/S程序在配置文件中配置
      if (string.IsNullOrWhiteSpace(filePath)) {       
        filePath = FileHelper.GetMapPath("/Dapper") + @"\";
      }
      var ar = Directory.GetFiles(filePath, "*.xml");

      ar.ToList().ForEach(x => _xmlFiles.Add(x));
      foreach (var item in _xmlFiles) {
        using (Stream stream = new FileStream(item, FileMode.Open, FileAccess.Read, FileShare.Read)) {
          XDocument doc = XDocument.Load(stream);
          if (doc == null) {
            return;
          }
          // 
          if (doc.Document != null) {
            var xElement = doc.Document.Element("statements");
            if (xElement != null) {
              var q = xElement.Elements("statement");
              foreach (var i in q) {
                var xAttribute = i.Attribute("id");
                var xAttribute2 = i.Attribute("cached");
                var xAttribute3 = i.Attribute("expired");
                var xAttribute4 = i.Attribute("primarykey");
                //一下几个属性只有用到存储过程分页的时候才需要填写
                var xAttribute5 = i.Attribute("sourcename");
                var xAttribute6 = i.Attribute("where");
                var xAttribute7 = i.Attribute("order");
                var xAttribute8 = i.Attribute("group");
                if (xAttribute != null) {
                  string key = xAttribute.Value;
                  string text = i.Value;

                  if (string.IsNullOrEmpty(key) || string.IsNullOrWhiteSpace(text))
                    return;

                  if (Dic.ContainsKey(key))
                    throw new ApplicationException(string.Format("{0} repeate!", key));

                  Dic[key] = new SqlStatement {
                    IsCached = xAttribute2 != null && (bool.Parse(xAttribute2.Value)),
                    StatementId = key,
                    StatementText = i.Value,
                    Expired = xAttribute3 == null ? 0 : int.Parse(xAttribute3.Value),
                    PrimaryKey = xAttribute4 == null ? "none" : xAttribute4.Value,
                    SourceName = xAttribute5 == null ? "none" : xAttribute5.Value,
                    Where = xAttribute6 == null ? "" : xAttribute6.Value,
                    Order = xAttribute7 == null ? "" : xAttribute7.Value,
                    Group = xAttribute8 == null ? "" : xAttribute8.Value
                  };
                }
              }
            }
          }
        }
      }*/
    }

    public bool SetStatement(string key, SqlStatement value) {
      if (string.IsNullOrEmpty(key))
        return false;

      SqlStatement os;
      if (Dic.ContainsKey(key)) {
        Dic.TryRemove(key, out os);
        Dic[key] = value;
        return true;
      }
      return false;
    }

    private static void ClearCollection() {
      _xmlFiles = new ConcurrentBag<string>();
      Dic.Clear();
    }

    /// <summary>
    /// 读入sql
    /// </summary>
    /// <param name="sId"></param>
    /// <returns></returns>
    public static SqlStatement ReadStatement(string sId) {
      if (Dic.ContainsKey(sId))
        return Dic[sId];
      throw new KeyNotFoundException(string.Format("{0} not found!", sId));
    }

    /// <summary>
    /// Velocity使用模板引擎处理复杂的SQL逻辑
    /// </summary>
    /// <param name="sId"></param>
    /// <param name="parameters"></param>
    /// <returns></returns>
    public static SqlStatement ReadStatement(string sId, IDictionary<string, object> parameters) {
      SqlStatement result;
      if (Dic.ContainsKey(sId))
        result = Dic[sId];
      else {
        throw new KeyNotFoundException(string.Format("{0} not found!", sId));
      }

      if (parameters == null)
        return result;

      var context = new VelocityContext();

      foreach (var pa in parameters) {
        context.Put(pa.Key, pa.Value);
      }

      string result1 = string.Empty;
      using (var writer = new StringWriter()) {
        Velocity.Evaluate(context, writer, "", result.StatementText);
        result1 = writer.ToString();
      }
      return new SqlStatement() { Expired = result.Expired, IsCached = result.IsCached, PrimaryKey = result.PrimaryKey, StatementId = result.StatementId, StatementText = result1 };
    }
  }
}
